﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Permissions;
using Microsoft.SharePoint;
using PS.Practices.Provisioner.Provisioner.Util;
using PS.Practices.SiteBuilder.Features.Schema;
using PS.Practices.Util;

namespace PS.Practices.Provisioner._14.Template.Features.PS.Practices.ProvisionerUI.ProvisionerUI
{
    /// <summary>
    /// List Item Events
    /// </summary>
    public class ProvisionerUI : SPItemEventReceiver
    {
        public class HandleEventFireing : SPWebEventReceiver
        {
            public HandleEventFireing()
            {
            }

            public void CustomDisableEventFiring()
            {
                this.EventFiringEnabled = false;
            }

            public void CustomEnableEventFiring()
            {
                this.EventFiringEnabled = true;
            }

        }

        public override void ItemUpdated(SPItemEventProperties properties)
        {
            base.ItemUpdated(properties);

            ProvisionWeb(properties);
        }

        /// <summary>
        /// An item has been updated
        /// </summary>
        public override void ItemAdded(SPItemEventProperties properties)
        {
            base.ItemAdded(properties);

            ProvisionWeb(properties);
        }

        private void ProvisionWeb(SPItemEventProperties properties)
        {
            SPWeb spWeb = properties.Web;
            SPListItem spListItem = properties.ListItem;
            SPList spList = properties.List;
            Dictionary<string, string> props = new Dictionary<string, string>();

            //Package the list properties
            props = spListItem.ContentType.Fields.OfType<SPField>().ToDictionary(
                field => field.Title,
                field => ListUtil.TryGetListItemProperty(spListItem, field.Title).ToString());

            //TODO make this into a one-time timer job instead
            //Provision the new web
            SPListItem provisionerItem = LocateGalleryProvisionItem(spListItem);
            var webUrl = ParserUtil.ReplaceAllPropertyFields(ListUtil.TryGetListItemProperty(provisionerItem, "WebUrl").ToString(), props);
            var webName = ParserUtil.ReplaceAllPropertyFields(ListUtil.TryGetListItemProperty(provisionerItem, "WebTitle").ToString(), props);
            var template = spWeb.GetWebTemplate((uint)1033, ListUtil.TryGetListItemProperty(provisionerItem, "Templates").ToString());

            HandleEventFireing hef = new HandleEventFireing();
            SPWeb provisionedWeb = null;
            try
            {
                hef.CustomDisableEventFiring();
                provisionedWeb = spWeb.Webs.Add(webUrl, webName, "This web was automatically provisioned.", 1033,
                                                      template, false, false);

                foreach (KeyValuePair<string, string> prop in props)
                {
                    provisionedWeb.AllProperties["ProvisionerProp_" + prop.Key] = prop.Value;
                    provisionedWeb.Update();
                }

                // Process the web
                var i = new Interpreter();
                var locatedScript = provisionerItem["Script"].ToString();
                i.ProcessScript(provisionedWeb, locatedScript);
            }
            finally
            {
                hef.CustomEnableEventFiring();

                if (provisionedWeb != null)
                    provisionedWeb.Dispose();
            }
        }

        private SPListItem LocateGalleryProvisionItem(SPListItem item)
        {
            var cTypeName = item.ContentType.Name;

            var rootWeb = item.ParentList.ParentWeb.Site.RootWeb;
            var provScriptList = rootWeb.Lists["Provisioner Scripts"];

            var query = new SPQuery
            {

                Query =
                    String.Format(
                    "<Where><Eq><FieldRef Name='ContentType0'/><Value Type='Text'>{0}</Value></Eq></Where>",
                    cTypeName),
                RowLimit = Constants.SpQueryRowLimit
            };

            SPListItemCollection myItems = provScriptList.GetItems(query);

            if (myItems.Count > 0)
            {
                return myItems[0];
            }

            return null;
        }
    }
}
